/*
 * ============================================================================
 *
 *       Filename:  swap.c
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  2013年04月28日 10时27分56秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  jianxi sun (jianxi), ycsunjane@gmail.com
 *   Organization:  
 *
 * ============================================================================
 */
#include <stdio.h>
#include <stdint.h>

typedef unsigned char uchar;

/* Get best performance when len is huge */
void endian_swap(uint8_t *data,uint32_t len)
{
	int i;
	for(i=0;i<len/2;i++){
		*(data+len-i-1) ^= *(data+i);
		*(data+i) ^= *(data+len-i-1);
		*(data+len-i-1) ^= *(data+i);
	}
}

uint16_t swap_16(uint16_t data)
{
	return (data << 8) | (data >> 8);
}

/* XXX i386 shift instruction uses a five bit wide field for the number of 
 * bits to shift a 32 bit operand by*/
uint32_t swap_32(uint32_t data)
{
	uchar *ptr = (uchar *)&data;
	return (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]);
}

/* HACK inefficient*/
uint64_t swap_64(uint64_t data)
{
	uint64_t tmp;
	uchar *ptr = (uchar *)&tmp;
	ptr[0] = data >> 56;
	ptr[1] = data >> 48;
	ptr[2] = data >> 40;
	ptr[3] = data >> 32;
	ptr[4] = data >> 24;
	ptr[5] = data >> 16;
	ptr[6] = data >> 8;
	ptr[7] = data;
	return tmp;
}

uint16_t swap_short(uint16_t data)
{
	return (data << 8) | (data >> 8);
}

uint32_t swap_word(uint32_t data)
{
	return ((data & 0x000000FF) << 24) |
		((data & 0x0000FF00) << 8) |
		((data & 0x00FF0000) >> 8) |
		((data & 0xFF000000) >> 24);
}

uint64_t swap_dword(uint64_t data)
{
	return ((data & 0x00000000000000FFULL) << 56) |
		((data & 0x000000000000FF00ULL) << 40)|
		((data & 0x0000000000FF0000ULL) << 24)|
		((data & 0x00000000FF000000ULL) << 8) |
		((data & 0x000000FF00000000ULL) >> 8) |
		((data & 0x0000FF0000000000ULL) >> 24)|
		((data & 0x00FF000000000000ULL) >> 40)|
		((data & 0xFF00000000000000ULL) >> 56);
}

int main()
{
	uint64_t data = 0x1122334455667788;
	printf("Origin: 0x%lx\n",data);

	printf("Swap16: 0x%x\n",swap_16((uint16_t)data));
	printf("Swap32: 0x%x\n",swap_32((uint32_t)data));
	printf("Swap64: 0x%lx\n",swap_64(data));

	printf("Swap16: 0x%x\n",swap_short((uint16_t)data));
	printf("Swap32: 0x%x\n",swap_word((uint32_t)data));
	printf("Swap64: 0x%lx\n",swap_dword(data));

	endian_swap((uint8_t *)&data,sizeof(data));
	printf("RAW_swap: 0x%lx\n",data);
	return 0;
}
